//=============================================================================
// System  : MatchKit
// File    : FieldOrProperty.cs
// Author  : Fabio Bussu  (matchkit@fabiobussu.it)
// Updated : 04/16/2013
// Note    : Copyright 2013, Fabio Bussu, All rights reserved
//
// This code is published under the Microsoft Public License (Ms-PL). A copy
// of the license should be distributed with the code.  It can also be found
// at the project website: http://matchkit.codeplex.com. This notice, the
// author's name, and all copyright notices must remain intact in all
// applications, documentation, and source files.
//
// Version     Date     Who  Comments
// ============================================================================
// 1.0.0.0  04/16/2013   FB  First draft
//=============================================================================
using System;
using System.Collections.Generic;
using System.Reflection;

namespace MatchKit.ObjectMapping
{
	struct FieldOrProperty
	{
		public readonly MemberInfo Member;
		private PropertyInfo _property;
		private FieldInfo _field;

		public FieldOrProperty(MemberInfo member)
		{
			if (member == null)
				throw new ArgumentNullException("member", "member cannot be null");
			if (!(member is FieldInfo)
				&& !(member is PropertyInfo))
				throw new ArgumentNullException("member", "member must be a field or  property");
			Member = member;
			_property = member is PropertyInfo ? (PropertyInfo)member : null;
			_field = member is FieldInfo ? (FieldInfo)member : null;
		}

		public bool CanRead
		{
			get
			{
				if (_field != null)
					return true;
				else
					return _property.CanRead;
			}
		}

		public bool IsIndexed
		{
			get
			{
				if (_field != null)
					return false;
				else
					return _property.GetIndexParameters().Length != 0;
			}
		}

		public bool IsStatic
		{
			get
			{
				if (_field != null)
					return _field.IsStatic;
				else
					return _property.GetAccessors(true)[0].IsStatic;
			}
		}

		public bool IsConst
		{
			get
			{
				if (_property != null)
				{
					return false;
				}
				else
				{
					return ((_field.Attributes & FieldAttributes.Static) != 0 && (_field.Attributes & FieldAttributes.InitOnly) != 0)
						|| (_field.Attributes & FieldAttributes.Literal) != 0;
				}
			}
		}

		public bool IsReadOnly
		{
			get
			{
				if (_property != null)
				{
					return !_property.CanWrite;
				}
				else
				{
					return (_field.Attributes & FieldAttributes.InitOnly) != 0
						|| (_field.Attributes & FieldAttributes.Literal) != 0;
				}
			}
		}

		public string FullName
		{
			get { return Member.DeclaringType.FullName + "." + Member.Name; }
		}

		public T GetCustomAttribute<T>()
			where T : Attribute
		{
			return ReflectionUtils.GetAttribute<T>(Member);
		}

		public IEnumerable<T> GetCustomAttributes<T>()
			where T: class
		{
			foreach (var attr in Member.GetCustomAttributes(true))
			{
				var t = attr as T;
				if (t != null)
					yield return t;
			}
		}

		public Type Type
		{
			get
			{
				if (_property != null)
					return _property.PropertyType;
				else
					return _field.FieldType;
			}
		}

		public Type DeclaringType
		{
			get
			{
				return Member.DeclaringType;
			}
		}

		public string Name
		{
			get
			{
				return Member.Name;
			}
		}

		public object GetValue(object instance)
		{
			if (_property != null)
				return _property.GetValue(instance, null);
			else
				return _field.GetValue(instance);
		}

		public void SetValue(object instance, object value)
		{
			if (_property != null)
				_property.SetValue(instance, value, null);
			else
				_field.SetValue(instance, value);
		}
	}
}
